#include "StdAfx.h"
#include "Register.h"

static unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
static FieldType gettype(const char* cp);
template<int n>
struct _N
{
    enum { V = n + _N<n-1>::V};
};
template<>
struct _N<0>
{
    enum {V = 0};
};
int mainxxx()
{
    int value = _N<100>::V;
    return 0;
}
CRegister::CRegister(void)
:m_address(0)
,m_value(0)
,m_bitcount(0)
{
}

CRegister::~CRegister(void)
{
}

CRegister::CRegister(const CRegister& rhs)
{
    this->m_address = rhs.m_address;
    this->m_bitcount = rhs.m_bitcount;
    this->m_description = rhs.m_description;
    this->m_fields = rhs.m_fields;
    this->m_name = rhs.m_name;
    this->m_value = rhs.m_value;
    for(size_t i=0;i<m_fields.size();i++){
        m_fields[i].m_base = this;
    }
}

CRegister& CRegister::operator=(const CRegister& rhs)
{
    this->m_address = rhs.m_address;
    this->m_bitcount = rhs.m_bitcount;
    this->m_description = rhs.m_description;
    this->m_fields = rhs.m_fields;
    this->m_name = rhs.m_name;
    this->m_value = rhs.m_value;
    for(size_t i=0;i<m_fields.size();i++){
        m_fields[i].m_base = this;
    }
    return *this;
}

bool CRegister::Load(TiXmlElement* regEle)
{
    bool res = true;
    if(!regEle)return false;

    const char* strtp = regEle->Attribute ("name");
    m_name = strtp ? strtp : "<unknown>";

    strtp = regEle->Attribute ("description");
    m_description = strtp ? strtp : "<unknown>";

    strtp = regEle->Attribute ("address");
    m_address = simple_strtoul(strtp,0,0);

    strtp = regEle->Attribute ("bitcount");
    m_bitcount = simple_strtoul(strtp,0,0);

    strtp = regEle->Attribute ("default");
    m_value = simple_strtoul(strtp,0,0);

    TiXmlNode* node = regEle->FirstChildElement("field");
    if(!node)return false;
    TiXmlElement* fieldEle = node->ToElement();
    while(fieldEle){
        CField fd(this);
        if(fd.Load(fieldEle)){
            m_fields.push_back(fd);
        }
        fieldEle = fieldEle->NextSiblingElement("field");
    }

    return res;
}

CRegList::CRegList(const char* fileName)
{
    Load(fileName);
}

bool CRegList::Load(const char* fileName)
{
    bool res = false;
    TiXmlDocument doc( "regcfg.xml" );
    res = doc.LoadFile();
    if(!res)return res;

    TiXmlNode* node = 0;
    TiXmlElement* configElement = 0;
    TiXmlElement* itemElement = 0;

    node = doc.FirstChild( "regconfig" );
    if(!node)return false;
    
    configElement = node->ToElement();
    if(!configElement)return false;

    node = configElement->FirstChildElement("reg");
    if(!node)return false;

    itemElement = node->ToElement();

    while(itemElement){
        CRegister reg;
        if(reg.Load(itemElement)){
            push_back(reg);
        }
        itemElement = itemElement->NextSiblingElement("reg");
    }

    return res;
}

CField::CField(const CField& rhs)
{
    this->m_name = rhs.m_name;
    this->m_description = rhs.m_description;
    this->m_start = rhs.m_start;
    this->m_end = rhs.m_end;
    this->m_type = rhs.m_type;
    this->m_values = rhs.m_values;
    this->m_base = rhs.m_base;
    this->m_vlist = rhs.m_vlist;
}

CField& CField::operator=(const CField& rhs)
{
    this->m_name = rhs.m_name;
    this->m_description = rhs.m_description;
    this->m_start = rhs.m_start;
    this->m_end = rhs.m_end;
    this->m_type = rhs.m_type;
    this->m_values = rhs.m_values;
    this->m_vlist = rhs.m_vlist;
    this->m_base = rhs.m_base;
    return *this;
}
bool CField::Load(TiXmlElement* fieldEle)
{
    bool res = true;
    if(!fieldEle)return false;

    const char* strtp = fieldEle->Attribute ("name");
    m_name = strtp ? strtp : "<unknown>";

    strtp = fieldEle->Attribute ("description");
    m_description = strtp ? strtp : "<unknown>";

    strtp = fieldEle->Attribute ("bitstart");
    m_start = simple_strtoul(strtp,0,0);

    strtp = fieldEle->Attribute ("bitend");
    m_end = simple_strtoul(strtp,0,0);

    strtp = fieldEle->Attribute ("type");
    m_type = gettype(strtp);

    if(m_type == FT_value)return true;

    TiXmlNode* node = fieldEle->FirstChildElement("value");
    if(!node)return false;
    TiXmlElement* valEle = node->ToElement();
    while(valEle){
        strtp = valEle->Attribute ("value");
        DWORD val = simple_strtoul(strtp,0,0);
        strtp = valEle->Attribute ("description");
        strtp = strtp ? strtp : "<unknown>";
        m_values[val] = strtp;
        m_vlist.push_back(val);
        valEle = valEle->NextSiblingElement("value");
    }
    return true;
}

string getFormatCode(DWORD bitcnt)
{
    char tp[16];
    sprintf(tp,"0x%%0%dX",(bitcnt+3)/4);
    return tp;
}

string CField::Value() 
{
    return m_name + " - " + ValueAbs();
}

string CField::ValueAbs()
{
    if(m_type == FT_value){
        char tp[256];
        sprintf(tp,getFormatCode(m_end-m_start+1).c_str(),getValue());
        return tp;
    }else{
        if(m_values.find(getValue()) != m_values.end()){
            return m_values[getValue()];
        }else{
            char tp[256];
            char fmt[128];
            sprintf(fmt,"<Unknown> %s",getFormatCode(m_end-m_start+1).c_str());
            sprintf(tp,fmt,getValue());
            return tp;
        }
    }
}

DWORD CField::getValue()
{
    DWORD base = m_base->m_value;
    base>>=m_start;
    base &= ((1<<(m_end-m_start+1))-1);
    return base;
}

int CField::getIndex(DWORD value)
{
    vector<DWORD>::size_type i=0;
    for(i=0;i<m_vlist.size();i++){
        if(value == m_vlist[i])return (int)i;
    }
    return (int)i;
}

DWORD  CField::setValueAbs(DWORD val)
{
    DWORD base = m_base->m_value;
        DWORD mask = ~((1<<(m_end-m_start+1))-1);
        mask <<= m_start;
        base &= mask;
        val &= ~mask;
        base |= val<<m_start;
    m_base->m_value = base;
    return base;
}

DWORD  CField::setValue(DWORD index)
{
    DWORD base = m_base->m_value;
    if(index < m_vlist.size()){
        DWORD mask = ~((1<<(m_end-m_start+1))-1);
        mask <<= m_start;
        mask |= ((1<<m_start)-1);
        base &= mask;
        base |= m_vlist[index]<<m_start;
    }
    m_base->m_value = base;
    return base;
}

void CField::UpdateValue(const char* val)
{
    if(m_type == FT_value){
        DWORD v = simple_strtoul(val,0,0);
        setValueAbs(v);
    }else{
        string str = m_name + " - ";
        val += str.length();
        map<DWORD,string>::iterator it = m_values.begin();
        for(;it!=m_values.end();it++){
            if(it->second == val){
                setValue(getIndex(it->first));
            }
        }
    }
}




static FieldType gettype(const char* cp)
{
    if(!cp)return FT_enum;
    if(!cp[0])return FT_enum;
    switch(cp[0]){
        case 'b': return FT_bool;
        case 'v': return FT_value;
    }
    return FT_enum;
}



static unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
{
	unsigned long result = 0,value;

    if((!cp) || (!cp[0]))return 0;
	if (*cp == '0') {
		cp++;
		if ((*cp == 'x') && isxdigit(cp[1])) {
			base = 16;
			cp++;
		}else if ((*cp == 'b') && isxdigit(cp[1])) {
			base = 2;
			cp++;
		}
		if (!base) {
			base = 8;
		}
	}
	if (!base) {
		base = 10;
	}
	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
	    ? toupper(*cp) : *cp)-'A'+10) < base) {
		result = result*base + value;
		cp++;
	}
	if (endp)
		*endp = (char *)cp;
	return result;
}


